package org.springframework.util;

import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Sets;
import lombok.Data;

import java.util.*;
import java.util.function.Supplier;

public final class AliasUtils {

    @Data
    public static class AliasChains<T>
            extends AbstractCollection<AliasChain<T>> {
        private List<AliasChain<T>> aliasChainList = new ArrayList<>();

        public void merge(T... elementArr) {
            merge(new AliasChain<>(elementArr));
        }

        public void merge(AliasChains<T> otherAliasChains) {
            List<AliasChain<T>> otherAliasChainList = otherAliasChains.getAliasChainList();
            for (AliasChain<T> aliasChain : otherAliasChainList) {
                merge(aliasChain);
            }
        }

        public void merge(AliasChain<T> aliasChain) {
            for (AliasChain<T> existAliasChain : aliasChainList) {
                if (existAliasChain.anyMatch(aliasChain)) {
                    existAliasChain.elements.addAll(aliasChain.getElements());
                    return;
                }
            }

            aliasChainList.add(aliasChain);
        }

        @Override
        public Iterator<AliasChain<T>> iterator() {
            return aliasChainList.iterator();
        }

        @Override
        public int size() {
            return aliasChainList.size();
        }
    }

    @Data
    public static class AliasChain<T> {
        private Set<T> elements;
        private Supplier valueSupplier;

        public AliasChain(T... elements) {
            this(Sets.newHashSet(elements));
        }

        public AliasChain(Set<T> elements) {
            this.elements = elements;
        }

        private boolean anyMatch(AliasChain<T> other) {
            Set<T> others = other.getElements();
            return elements.stream().anyMatch(others::contains);
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this).add("elements", Joiner.on(" <--> ").join(elements)).toString();
        }
    }
}


